
template <class T, class TAlloc> inline
GnTArray<T, TAlloc>::GnTArray( gtuint uiMaxSize, gtuint uiGrowBy )
{
	mMaxSize = (gtuint)uiMaxSize;
	mGrowBy = (gtuint)uiGrowBy;
	mSize = 0;
	mESize = 0;

	if (mMaxSize > 0)
	{
		m_pBase = TAlloc::Allocate(mMaxSize);
		GnAssert(m_pBase);
	}
	else
	{
		m_pBase = 0;
	}
}

template <class T, class TAlloc> inline
GnTArray<T, TAlloc>::~GnTArray()
{
	TAlloc::Deallocate(m_pBase);
}

template <class T, class TAlloc> inline
T* GnTArray<T, TAlloc>::GetBase()
{
	return m_pBase;
}

template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::GetSize() const
{
	return mSize;
}

template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::GetEffectiveSize() const
{
	return mESize;
}

template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::GetAllocatedSize() const
{
	return mMaxSize;
}

template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::GetGrowBy() const
{
	return mGrowBy;
}

template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::SetSize(gtuint uiMaxSize)
{


	if (uiMaxSize == mMaxSize)
	{
		return;
	}

	// If the number of slots gets smaller, the elements in the unwanted
	// slots must be zeroed in case class T has side effects that must occur.
	// For example, if T is a smart pointer class, then decrementing the ref
	// count must occur.
	gtuint i;
	if (uiMaxSize < mSize)
	{
		for (i = (gtuint)uiMaxSize; i < mSize; i++)
		{
			if (m_pBase[i] != T(0))
			{
				m_pBase[i] = T(0);
				mESize--;
			}
		}

		mSize = uiMaxSize;
	}

	T* pSaveBase = m_pBase;
	mMaxSize = uiMaxSize;
	if (uiMaxSize > 0)
	{
		// allocate a new array
		m_pBase = TAlloc::Allocate(mMaxSize);
		GnAssert(m_pBase);

		// copy old array to new array
		for (i = 0; i < mSize; i++)
		{
			m_pBase[i] = pSaveBase[i];
		}
		// initialize new memory
		for (i = mSize; i < mMaxSize; i++)
		{
			m_pBase[i] = T(0);
		}


	}
	else
	{
		m_pBase = 0;
	}

	// delete old array
	TAlloc::Deallocate(pSaveBase);
}

template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::SetGrowBy(gtuint uiGrowBy)
{
	mGrowBy = uiGrowBy;
}

template <class T, class TAlloc> inline
const T& GnTArray<T, TAlloc>::GetAt(gtuint uiIndex) const
{
	GnAssert(uiIndex < mMaxSize);
	return m_pBase[uiIndex];
}

template <class T, class TAlloc> inline
 T& GnTArray<T, TAlloc>::GetAt(gtuint uiIndex)
{
	GnAssert(uiIndex < mMaxSize);
	return m_pBase[uiIndex];
}

template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::SetAt(gtuint uiIndex, const T& element)
{
	GnAssert(uiIndex < mMaxSize);

	if (uiIndex >= mSize)
	{
		mSize = uiIndex+1;
		if (element != T(0))
		{
			mESize++;
		}
	}
	else
	{
		if (element != T(0))
		{
			if (m_pBase[uiIndex] == T(0))
			{
				mESize++;
			}
		}
		else
		{
			if (m_pBase[uiIndex] != T(0))
			{
				mESize--;
			}
		}
	}

	m_pBase[uiIndex] = element;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::SetAtGrow(gtuint uiIndex,
												 const T& element)
{
	if (uiIndex >= mMaxSize)
	{
		SetSize(uiIndex + mGrowBy);
	}

	SetAt(uiIndex, element);
	return uiIndex;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::Add(const T& element)
{
	return SetAtGrow(mSize, element);
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::AddFirstEmpty(const T& element)
{
	if (element == T(0))
	{
		return 0xffffffff;
	}

	for (gtuint i = 0; i < mSize; i++)
	{
		if (m_pBase[i] == T(0))
		{
			// empty slot - add here
			m_pBase[i] = element;
			mESize++;
			return i;
		}
	}

	// no empty slots - add at end
	return SetAtGrow(mSize, element);
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
T GnTArray<T, TAlloc>::RemoveAt(gtuint uiIndex)
{
	if (uiIndex >= mSize)
	{
		return T(0);
	}

	T element = m_pBase[uiIndex];
	m_pBase[uiIndex] = T(0);

	if (element != T(0))
	{
		mESize--;
	}

	if (uiIndex == mSize - 1)
	{
		mSize--;
	}

	return element;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
T GnTArray<T, TAlloc>::RemoveAtAndFill(gtuint uiIndex)
{
	if (uiIndex >= mSize)
	{
		return T(0);
	}

	mSize--;
	T element = m_pBase[uiIndex];

	m_pBase[uiIndex] = m_pBase[mSize];
	m_pBase[mSize] = T(0);

	if (element != T(0))
	{
		mESize--;
	}

	return element;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
T GnTArray<T, TAlloc>::RemoveEnd()
{
	if (mSize == 0)
		return T(0);

	mSize--;
	T element = m_pBase[mSize];
	m_pBase[mSize] = T(0);

	if (element != T(0))
	{
		mESize--;
	}

	return element;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::RemoveAll()
{
	// The elements in the to-be-removed slots must be zeroed in case class
	// T has side effects that must occur.  For example, if T is a smart
	// pointer class, then decrementing the ref count must occur.
	for (gtuint i = 0; i < mSize; i++)
	{
		m_pBase[i] = T(0);
	}

	mSize = 0;
	mESize = 0;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
gtuint GnTArray<T, TAlloc>::Remove(const T& element)
{
	if (element != T(0))
	{
		for (gtuint i = 0; i < mSize; i++)
		{
			if (m_pBase[i] == element)
			{
				m_pBase[i] = T(0);

				mESize--;
				if (i == mSize - 1)
					mSize--;

				return i;
			}
		}
	}

	return (gtuint)~0;
}
//---------------------------------------------------------------------------
template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::Compact()
{
	if (mESize == mSize)
	{
		return;
	}

	// move elements to contiguous memory at beginning of array
	if (mESize)
	{
		for (gtuint i = 0, j = 0; i < mSize; i++)
		{
			if (m_pBase[i] != T(0))
			{
				if (m_pBase[j] != m_pBase[i])
				{
					m_pBase[j] = m_pBase[i];
				}
				j++;
			}
		}
	}

	// downsize storage
	T* pSaveBase = m_pBase;
	mSize = mESize;
	mMaxSize = mSize;
	if (mMaxSize > 0)
	{
		m_pBase = TAlloc::Allocate(mMaxSize);
		GnAssert(m_pBase);

		// copy old array to new array
		for (gtuint i = 0; i < mSize; i++)
		{
			m_pBase[i] = pSaveBase[i];
		}
	}
	else
	{
		m_pBase = 0;
	}

	// delete old array
	TAlloc::Deallocate(pSaveBase);
}

template <class T, class TAlloc> inline
void GnTArray<T, TAlloc>::UpdateSize()
{
	while (mSize > 0)
	{
		if (m_pBase[mSize - 1] != T(0))
		{
			break;
		}

		mSize--;
	}
}

template <class T> inline
GnTObjectArray<T>::GnTObjectArray(gtuint uiMaxSize,
	gtuint uiGrowBy) : GnTArray<T, GnTNewInterface<T> >(uiMaxSize, uiGrowBy)
{
}

template <class T> inline
GnTPrimitiveArray<T>::GnTPrimitiveArray(gtuint uiMaxSize,
	gtuint uiGrowBy) : GnTArray<T, GnTMallocInterface<T> >( uiMaxSize, uiGrowBy)
{
}
